package me.ohaga
{
	import net.flashpunk.Entity;
	import net.flashpunk.FP;
	import net.flashpunk.Graphic;
	import net.flashpunk.Mask;
	import net.flashpunk.graphics.Image;
	import net.flashpunk.graphics.Spritemap;
	import net.flashpunk.utils.Input;
	import net.flashpunk.utils.Key;
	
	public class Player extends Entity
	{
		[Embed(source="/assets/gfx/player.png")] private static const PLAYER_IMG:Class;
		
		public static const WIDTH:Number = 40;
		public static const HEIGHT:Number = 40;
		public static const MAX_VEL_X:Number = 200;
		public static const MAX_VEL_Y:Number = 1000;
		public static const JUMP_FORCE:Number = 250;
		public static const MOVE_ACCEL:Number = 100;
		public static const MAX_ACCEL:Number = 200;
		
		private var _playerSprite:Spritemap = new Spritemap(PLAYER_IMG, WIDTH, HEIGHT);
		private var _onWall:String = "bottom";
		private var _acceleration:Number = 0;
		private var _velocityX:Number = 0;
		private var _velocityY:Number = 0;
		
		public function Player(x:Number=0, y:Number=0) {
			this.x = x;
			this.y = y;
			
			this.setHitbox(WIDTH,HEIGHT);
			this.graphic = _playerSprite;
		}
		
		override public function update():void {
			super.update();
			
			if (Input.pressed(Key.SPACE)) {
				doPower();
			}
			
			switch(frame) {
				case PlayerState.TRIANGLE:
					// MOVEMENT
					if (null == _onWall) {
						applyForce();
					} else {
						var newX:Number = x;
						var newY:Number = y;
						
						var canMoveDown:Boolean = _onWall == "left" || _onWall == "right";
						var canMoveUp:Boolean = canMoveDown;
						var canMoveLeft:Boolean = _onWall == "bottom" || _onWall == "top";
						var canMoveRight:Boolean = canMoveLeft;
						
						if (canMoveRight && Input.pressed(Key.RIGHT)) {
							movePlayerTo(x + WIDTH, y, "block", "right");
						} else if (canMoveLeft && Input.pressed(Key.LEFT)) {
							movePlayerTo(x - WIDTH, y, "block", "left");
						} else if (canMoveUp && Input.pressed(Key.UP)) {
							movePlayerTo(x, y - HEIGHT, "block", "top");
						} else if (canMoveDown && Input.pressed(Key.DOWN)) {
							movePlayerTo(x, y + HEIGHT, "block", "bottom");
						}
					}
					
					break;
				case PlayerState.RECTANGLE: break;
				case PlayerState.CIRCLE:
					
					applyForce();
					
					var canJump:Boolean = isOnPlatform();
					
					if (canJump) {
						if (Input.pressed(Key.UP)) {
							_velocityY = -JUMP_FORCE;
						}
					}
					if (Input.check(Key.RIGHT)) {
						addAcceleration(MOVE_ACCEL);
					} else if (Input.check(Key.LEFT)) {
						addAcceleration(-MOVE_ACCEL);
					}
					
					break;
			}
			
			if (collide("exit", x, y)) {
				game.changeLevel();
			}
		}
		
		public function doPower():void {
			_playerSprite.setFrame(frame+1%3);
		}
		
		private function isOnPlatform():Boolean {
			return null != this.collide("block", x, y + 1);
		}
		
		public function movePlayerTo(x:Number, y:Number, solidType:Object = null, onWallIfCollide:String = null):Boolean {
			var oldX:Number = this.x;
			var oldY:Number = this.y;
			
			super.moveTo(x,y,solidType);
			
			if (oldX == this.x && oldY == this.y) {
				if (null == onWallIfCollide) {
					var collidedEntity:Entity = collide("block", x, y);
					if (collidedEntity) {
						if (collidedEntity.y > this.y) {
							onWallIfCollide = "bottom";
						}
					}
				}
				
				_onWall = onWallIfCollide;
				return false;
			}
			
			return true;
		}
		
		private function applyForce():void {
			addYForce(game.gravity*FP.elapsed);
			
			if (isOnPlatform() && _acceleration != 0) {
				var a:Number = _acceleration;
				addAcceleration((_acceleration > 0 ? -1 : 1)*game.friction*FP.elapsed);
				if (a > 0 && _acceleration < 0 || a < 0 && _acceleration > 0) {
					_acceleration = 0;
				}
			}
			
			addXForce(_acceleration*FP.elapsed);
			
			var newY:Number = y + _velocityY*FP.elapsed;
			var newX:Number = x + _velocityX*FP.elapsed;
			
			if (movePlayerTo(newX, newY, "block")) {
				_onWall = null;
			} else {
				_velocityY = 0;
				_velocityX = 0;
			}
		}
		
		private function addAcceleration(a:Number):Number {
			_acceleration += a;
			if (_acceleration > 0) {
				_acceleration = Math.min(_acceleration, MAX_ACCEL);
			} else {
				_acceleration = Math.max(_acceleration, -MAX_ACCEL);
			}
			return _acceleration;
		}
		
		private function addXForce(f:Number):Number {
			_velocityX = Math.min(_velocityX + f, MAX_VEL_X);
			_velocityX = Math.max(_velocityX + f, -MAX_VEL_X);
			return _velocityX;
		}
		private function addYForce(f:Number):Number {
			_velocityY = Math.min(_velocityY + f, MAX_VEL_Y);
			return _velocityY;
		}
				
		public function get frame():Number { return _playerSprite.frame; }
		
		private function get game():Game { return world as Game; }
	}
}